import { conn } from '@beshell/conn-ts/Connection'
import {AppModel} from '../AppModel'
import { I2C } from '../conn/I2C'
import { PartSlaver } from './PartBase'
import config from './config/BePoser.json'

declare var Vue: any

export class BePoser extends PartSlaver {

    // 四元数
    x = 0
    y = 0
    z = 0
    w = 0

    // 欧拉角
    pitch = 0
    roll = 0
    yaw = 0

    dataUpdateTime = 0

    public bAutoReadDMP = false
    private autoReadDMPDur = 0
    private autoReadDMPTimer: any = -1

    constructor(_model: AppModel){
        super(_model, config)
    }
    
    public isConnectionReady() {
        let sda = this.studs[1][0].bus?.findHostStud()
        let scl = this.studs[1][1].bus?.findHostStud()
        return !!(sda && scl)
    }

    public async remoteBegin() {
        if( !conn.isConnected ) {
            return
        }
        let code = this.generateBeginCode()
        console.log(code)
        if(!code){
            return
        }
        await conn.console.run(code)
    }

    public generateSetupCode(indent=0){
        return `${"\t".repeat(indent)}${this.remoteVar()} = new (require('besdk/driver/poser.js')) ()`
    }

    public generateBeginCode(indent=0) {
        let sda = this.studs[1][0].bus?.findHostStud()
        let scl = this.studs[1][1].bus?.findHostStud()
        if (!sda || !scl){
            console.log("poser wires is invalid", this)
            return ''
        }
        let cable = this.findCable(I2C)
        if(!cable) {
            console.log("poser cable is invalid", this)
            return ''
        }
        return `${"\t".repeat(indent)}${this.remoteVar()}.begin(${cable.name}, ${sda.gpio.name()}, ${scl.gpio.name()}, 400000)\n`
    }

    public async readRemote() {
        if( !conn.isConnected ) {
            return false
        }
        
        try{
            var data = await conn.console.callAsync(`resolve(await ${this.remoteVar()}.readDMP())`)
        }catch(e){
            console.error(e)
            return false ;
        }

        if(data) {
            this.x = data.x
            this.y = data.y
            this.z = data.z
            this.w = data.w
            
            // this.calculateEuler()

            Vue.set(this, "dataUpdateTime", Date.now())

            return true
        }

        return false
    }

    public calculateEuler() {
        this.pitch = -Math.asin(2.0 * (this.x * this.z - this.w * this.y)) * 57.3
        this.roll = Math.atan2(2.0 * (this.x * this.y + this.z * this.w), 1-2.0*(this.y * this.y + this.z * this.z))*57.3
        this.yaw =  Math.atan2(2.0 * (this.x * this.w + this.y * this.z), 1-2.0 * (this.z * this.z + this.w * this.w)) * 57.3 
    }


    private async autoReadDMPOnce() {
        if( await this.readRemote() ){
            // this.calculateEuler()
        }
        else {
            this.stopReadDMP()
            return
        }

        // next
        if(this.bAutoReadDMP && this.autoReadDMPDur>0) {
            this.autoReadDMPTimer = setTimeout(()=>this.autoReadDMPOnce(), this.autoReadDMPDur)
        }
    }

    public startReadDMP(dur=50) {
        this.bAutoReadDMP = true
        this.autoReadDMPDur = dur
        this.autoReadDMPOnce()
    }

    public stopReadDMP() {
        if(this.autoReadDMPTimer>=0) {
            clearTimeout(this.autoReadDMPTimer)
            this.autoReadDMPTimer = -1
        }
        this.bAutoReadDMP = false
        this.autoReadDMPDur = 0
    }
}